﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Data;
using System.Collections;
using System.Net;
using Kailua.WSSLists;
using System.Xml;
using System.Web.Services.Protocols;
using log4net;

namespace Kailua.net.windward.utils.ado.SPList.custom
{
    /// <summary>
    /// A connection for a SharePoint list data provider.
    /// </summary>
    public class SPListConnection : DbConnection
    {
        /// <summary>
        /// eg, open, closed, etc...
        /// </summary>
        private ConnectionState state;
        /// <summary>
        /// list web service adapter; makes the actual queries to the list web service
        /// </summary>
        public SPListWebServiceAdapter listServiceAdapter;

        private string connectionString;

        private static ILog log = LogManager.GetLogger(typeof(SPListConnection));

        #region Constructors
        /// <summary>
        /// Creates a default connection with no connection properties set.  You must set the connection string.
        /// </summary>
        public SPListConnection()
        {
            listServiceAdapter = new SPListWebServiceAdapter();
        }

        /// <summary>
        /// Creates a connection using the specified connection string.  The connection string should be like
        /// URL=URL;WEB={GUID};LIST={GUID};VIEW={GUID};USER=USERNAME;PASSWORD=PASSWORD;DOMAIN=DOMAIN;.
        /// </summary>
        /// <param name="connectionString"></param>
        public SPListConnection(string connectionString)
        {
            this.ConnectionString = connectionString;
            listServiceAdapter = new SPListWebServiceAdapter();
        }
        #endregion Constructors

        // we'll have to parse this connection string, and pull out the information
        // necesary to connect to the web service. eg, site, list, view...
        /// <summary>
        /// Gets or sets the connection string.
        /// </summary>
        public override string ConnectionString
        {
            get { return connectionString; }
            set { connectionString = value; }
        }

        /// <summary>
        /// Not supported.
        /// </summary>
        public int ConnectionTimeout
        {
            get { throw new NotSupportedException(); }
        }

        /// <summary>
        /// Not supported.
        /// </summary>
        public override string Database
        {
            get { throw new NotSupportedException(); }
        }

        /// <summary>
        /// Gets the connection state.
        /// </summary>
        public override ConnectionState State
        {
            get { return state; }
        }

        #region IDbConnection Members

        /// <summary>
        /// Not supported.
        /// </summary>
        /// <param name="il"></param>
        /// <returns></returns>
        public IDbTransaction BeginTransaction(IsolationLevel il)
        {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Not supported.
        /// </summary>
        /// <returns></returns>
        public IDbTransaction BeginTransaction()
        {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Not supported.
        /// </summary>
        /// <param name="databaseName"></param>
        public override void ChangeDatabase(string databaseName)
        {
            throw new NotSupportedException();
        }
        /// <summary>
        /// Closes the connection.
        /// </summary>
        public override void Close()
        {
            // since we're just hitting a web service, there isn't a 
            // connection like there is with a database...
            state = ConnectionState.Closed;
        }

        /// <summary>
        /// Creates an SPListCommand for this connection.
        /// </summary>
        /// <returns></returns>
        public IDbCommand CreateCommand()
        {
            SPListCommand cmd = new SPListCommand();
            cmd.Connection = this;
            return cmd;
        }


        /// <summary>
        /// Opens the connection.
        /// </summary>
        public override void Open()
        {
            // since we're just hitting a web service, there isn't a 
            // connection like there is with a database

            // maybe what I should do here is parse the connection string
            // and construct the lists service object
            parseConnectionString();

            // run test query
            try
            {
                Lists listService = new Lists();
                listService.PreAuthenticate = true;
                listService.Url = listServiceAdapter.serviceUrl;
                listService.Credentials = listServiceAdapter.credentials;
                XmlNode ndLists = listService.GetListCollection();
            }
            catch (SoapException ex)
            {
                string detail = ex.Detail.OuterXml;
                throw new Exception(detail, ex);
            }
            catch (Exception ex)
            {
                if (log.IsWarnEnabled)
                    log.Warn("Error occured opening SharePoint list connection.", ex);
                throw;
            }

            state = ConnectionState.Open;
        }

        #endregion IDbConnection Members

        #region IDisposable Members

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            ;
        }

        #endregion IDisposable Members

        /// <summary>
        /// Gets the info out of the connection string and assigns it to the
        /// listService.
        /// </summary>
        private void parseConnectionString()
        {
            Hashtable keyPairs = ParseConnectionString(ConnectionString);
            listServiceAdapter.serviceUrl = (string)keyPairs["URL"] + "/_vti_bin/Lists.asmx";
            listServiceAdapter.sListGuid = (string)keyPairs["LIST"];
            if (keyPairs.ContainsKey("WEB"))
                listServiceAdapter.sWebID = (string)keyPairs["WEB"];
            if (keyPairs.ContainsKey("VIEW"))
                listServiceAdapter.sViewGuid = (string)keyPairs["VIEW"];
            else
                listServiceAdapter.sViewGuid = string.Empty;
            string user = null;
            string password = null;
            string domain = null;
            if (keyPairs.ContainsKey("USER"))
            {
                user = (string)keyPairs["USER"];
                password = (string)keyPairs["PASSWORD"];
                if (keyPairs.ContainsKey("DOMAIN"))
                    domain = (string)keyPairs["DOMAIN"];
            }
            if (user != null)
            {
                if (domain != null)
                    listServiceAdapter.credentials = new NetworkCredential(user, password, domain);
                else
                    listServiceAdapter.credentials = new NetworkCredential(user, password);
            }
            else
                listServiceAdapter.credentials = System.Net.CredentialCache.DefaultNetworkCredentials;

        }
        /// <summary>
        /// Parses the connection string into a Hashtable.  The connection string must be of the
        /// form "KEY1=VAL1;KEY2=VAL2;...KEYN=VALN;".
        /// </summary>
        /// <param name="connStr"></param>
        /// <returns></returns>
        internal static Hashtable ParseConnectionString(string connStr)
        {
            // tokenize the declarations
            string[] tokens = connStr.Split(';');
            // split the declarations into key-pairs in a dictionary
            Hashtable hashtable = new Hashtable(tokens.Length);
            for (int i = 0; i < tokens.Length; i++)
            {
                if (tokens[i].Trim().Equals(string.Empty))
                    continue;
                string[] keyPair = tokens[i].Split('=');
                hashtable.Add(keyPair[0], keyPair[1]);
            }
            return hashtable;
        }
        /// <summary>
        /// Not supported.
        /// </summary>
        /// <param name="isolationLevel"></param>
        /// <returns></returns>
        protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
        {
            throw new NotSupportedException();
        }
        /// <summary>
        /// Creates a new database command.
        /// </summary>
        /// <returns></returns>
        protected override DbCommand CreateDbCommand()
        {
            return (DbCommand)CreateCommand();
        }
        /// <summary>
        /// Not supported.
        /// </summary>
        public override string DataSource
        {
            get { throw new NotSupportedException(); }
        }
        /// <summary>
        /// Not supported.
        /// </summary>
        public override string ServerVersion
        {
            get { throw new NotSupportedException(); }
        }
    }
}
